package com.csun.cmny.provider.service.impl;

import com.csun.cmny.base.enums.ErrorCodeEnum;
import com.csun.cmny.core.support.BaseService;
import com.csun.cmny.provider.dao.DmcCsunSleepDataActionMapper;
import com.csun.cmny.provider.exceptions.DmcBizException;
import com.csun.cmny.provider.model.constant.OldmanAppConstant;
import com.csun.cmny.provider.model.domain.DmcCsunSleepDataAction;
import com.csun.cmny.provider.model.domain.DmcCsunSleepDataInBed;
import com.csun.cmny.provider.model.dto.app.AppSleepDateQueryDto;
import com.csun.cmny.provider.model.dto.csunsleep.CsunSleepDataActionQueryDto;
import com.csun.cmny.provider.model.dto.csunsleep.CsunSleepDataInBedQueryDto;
import com.csun.cmny.provider.model.entity.TimeRange;
import com.csun.cmny.provider.model.vo.app.AppSingleDaySleepDataVo;
import com.csun.cmny.provider.model.vo.app.AppSleepRangeVo;
import com.csun.cmny.provider.service.DmcCsunSleepDataActionService;
import com.csun.cmny.provider.service.DmcCsunSleepDataHiService;
import com.csun.cmny.provider.service.DmcCsunSleepDataInBedService;
import com.csun.cmny.provider.utils.DateUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;

/**
 * @Auther: chisj chisj@foxmal.com
 * @Date: 2019-04-02 11:00
 * @Description: the class dmc csun sleep data action service impl
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class DmcCsunSleepDataActionServiceImpl extends BaseService<DmcCsunSleepDataAction>
        implements DmcCsunSleepDataActionService {

    @Resource
    private DmcCsunSleepDataActionMapper dmcCsunSleepDataActionMapper;

    @Resource
    private DmcCsunSleepDataHiService dmcCsunSleepDataHiService;

    @Resource
    private DmcCsunSleepDataInBedService dmcCsunSleepDataInBedService;

    @Override
    public AppSingleDaySleepDataVo getAppSingleDaySleepData(AppSleepDateQueryDto appSleepDateQueryDto) {

        //获取查询参数
        String date = appSleepDateQueryDto.getDate();
        Long deviceId = appSleepDateQueryDto.getDeviceId();

        //将获取的日期对象转化为从前一天12:00到今日12：00的时间对象
        TimeRange countSleepTimeRange = DateUtil.getYesterDayAndTodayDate(date);

        CsunSleepDataInBedQueryDto inBedQueryDto = new CsunSleepDataInBedQueryDto();
        inBedQueryDto.setDeviceId(deviceId);
        inBedQueryDto.setInBed(0);
        inBedQueryDto.setPageSize(65535);
        inBedQueryDto.setStartQueryTime(countSleepTimeRange.getStartTime());
        inBedQueryDto.setEndQueryTime(countSleepTimeRange.getEndTime());
        List<DmcCsunSleepDataInBed> dmcCsunSleepDataInBeds = dmcCsunSleepDataInBedService.queryCsunSleepDataInBedList(inBedQueryDto);

        //创建翻身查询对象
        CsunSleepDataActionQueryDto actionQuery = new CsunSleepDataActionQueryDto();
        actionQuery.setDeviceId(deviceId);
        actionQuery.setStartQueryTime(countSleepTimeRange.getStartTime());
        actionQuery.setEndQueryTime(countSleepTimeRange.getEndTime());

        //查询当日翻身时间信息
        List<DmcCsunSleepDataAction> actionList = queryCsunSleepDataActionList(actionQuery);

        if(dmcCsunSleepDataInBeds.size()<1 || actionList.size()<1){
            throw new DmcBizException(ErrorCodeEnum.DMC10067009);
        }

        //定义返回的vo对象
        AppSingleDaySleepDataVo appSingleDaySleepDataVo = new AppSingleDaySleepDataVo();

        List<AppSleepRangeVo> appSleepRangeVos = new LinkedList<>();

        //定义在床时长
        double countInBedTime = 0;

        //定义睡眠时长
        double countSleepTime = 0;

        //定义当日最佳入睡时间，晚于此时间的第一次入睡时间为当天夜间入睡时间
        Date fallAsleepTimeStandard = DateUtil.transformDateStringToYesterDayDate(date ,OldmanAppConstant.BEST_FALL_ASLEEP_TIME);

        //定义今日早上最佳起床时间，晚于此时间的第一次离床为起床时间；
        Date getBedTimeStandard = DateUtil.transformDateStringToDate(date,OldmanAppConstant.BEST_GET_BED_TIME);

        //内层循环指针暂存变量
        int temp = 0;

        //计算在床状态下的翻身间隔时间
        for(int i = 0,j = dmcCsunSleepDataInBeds.size();i<j;i++){

            //在床时长
            long inBedDuration = dmcCsunSleepDataInBeds.get(i).getDuration();

            //下床时刻
            Date inBedEndTime = dmcCsunSleepDataInBeds.get(i).getCreatedTime();

            //实际上床时刻 = 下床时刻 - 在床时长
            Date actualInBedStartTime = DateUtil.dateSubstractSeconds(inBedEndTime,(int)inBedDuration);

            //第一次计算时，上床时长早于统计开始时长，将上床时间设置为统计开始时间
            //之后按实际上床时刻计算
            Date inBedStartTime = i==0?countSleepTimeRange.getStartTime():actualInBedStartTime;

            //获取起床时间
            if(appSingleDaySleepDataVo.getGetBedTime() == null && inBedEndTime.after(getBedTimeStandard)){
                appSingleDaySleepDataVo.setGetBedTime(inBedEndTime);
            }

            countInBedTime += ((double) (inBedEndTime.getTime() -  inBedStartTime.getTime()))/(60*1000);

            //如果该次翻身时间早于本段下床时间
            for(int k=temp,h = actionList.size();actionList.get(k).getActionTime().before(inBedEndTime);k++){

                //定义翻身时刻
                Date actionTime = actionList.get(k).getActionTime();

                //如果该次翻身时间晚于本段上床时间 且开始统计时间小于翻身时间
                if(actionTime.after(inBedStartTime) && inBedStartTime.compareTo(actionTime) < 0){

                    //定义该次翻身到上次翻身的间隔时长
                    long actionDuration = actionList.get(k).getDuration();

                    //定义上次翻身时间
                    Date lasteActionTime = DateUtil.dateSubstractSeconds(actionTime,(int)actionDuration);

                    //定义睡眠开始时刻
                    Date sleepStartTime = lasteActionTime.before(inBedStartTime)?inBedStartTime:lasteActionTime;

                    //获取入睡时间
                    if(appSingleDaySleepDataVo.getFallAsleepTime() == null && sleepStartTime.after(fallAsleepTimeStandard)){
                        appSingleDaySleepDataVo.setFallAsleepTime(sleepStartTime);
                    }

                    //定义睡眠范围vo
                    AppSleepRangeVo thisSleepRange = caculateSleepTime(actionTime, inBedEndTime);

                    //如果是睡眠状态，加入睡眠时间到总睡眠时间
                    if(thisSleepRange.getSleepStatus() == OldmanAppConstant.LIGHT_SLEEP_STATUS || thisSleepRange.getSleepStatus() == OldmanAppConstant.DEEP_SLEEP_STATUS){
                        countSleepTime += thisSleepRange.getSleepTime();
                    }

                    //如果该次【体动时间】的下次【体动时间】超过或等于【下床时间】，那么该次【体动时间】到【下床时间】的这段【睡眠时长】需要单独计算
                    if(actionList.get(k+1).getActionTime().compareTo(inBedEndTime) >= 0){

                        //定义睡眠范围vo
                        AppSleepRangeVo thisLastSleepRange = caculateSleepTime(actionTime, inBedEndTime);

                        //如果是睡眠状态，加入睡眠时间到总睡眠时间
                        if(thisSleepRange.getSleepStatus() == OldmanAppConstant.LIGHT_SLEEP_STATUS || thisSleepRange.getSleepStatus() == OldmanAppConstant.DEEP_SLEEP_STATUS){
                            countSleepTime += thisSleepRange.getSleepTime();
                        }
                        //将该段睡眠加入睡眠统计
                        appSleepRangeVos.add(thisLastSleepRange);
                    }

                    //将该段睡眠加入睡眠统计
                    appSleepRangeVos.add(thisSleepRange);
                }

                //调整指针位置，下一次循环时，不需要重新循环
                temp = k;
            }

            //计算睡眠得分
            int sleepGrade = countSleepTime>OldmanAppConstant.BEST_SLEEP_TIME?(int)(OldmanAppConstant.BEST_SLEEP_TIME/countSleepTime*100):(int)(countSleepTime/OldmanAppConstant.BEST_SLEEP_TIME*100);
            appSingleDaySleepDataVo.setSleepGrade(sleepGrade);
        }

        //填充数据
        appSingleDaySleepDataVo.setCountInBedTime(countInBedTime);
        appSingleDaySleepDataVo.setAppSleepRangeVos(appSleepRangeVos);
        appSingleDaySleepDataVo.setCountSleepTime(countSleepTime);
        appSingleDaySleepDataVo.setCountActionTimes(actionList.size());
        return appSingleDaySleepDataVo;
    }

    @Override
    public List<DmcCsunSleepDataAction> queryCsunSleepDataActionList(CsunSleepDataActionQueryDto csunSleepDataActionQueryDto) {
        return dmcCsunSleepDataActionMapper.queryCsunSleepDataActionList(csunSleepDataActionQueryDto);
    }

    @Override
    public DmcCsunSleepDataAction getLatestActionDataByDeviceId(Long deviceId) {
        return dmcCsunSleepDataActionMapper.getLatestActionDataByDeviceId(deviceId);
    }

    @Override
    public Integer countActionAlertTimes(AppSleepDateQueryDto appSleepDateQueryDto) {
        return dmcCsunSleepDataActionMapper.countActionAlertTimes(appSleepDateQueryDto);
    }

    //根据起止时间计算睡眠时长
    public AppSleepRangeVo caculateSleepTime(Date startTime,Date endTime){

        AppSleepRangeVo appSleepRangeVo = new AppSleepRangeVo();

        //计算睡眠时长
        double sleepDuration = ((double)(endTime.getTime() - startTime.getTime()))/(1000*60);
        appSleepRangeVo.setSleepTime(sleepDuration);
        appSleepRangeVo.setStartTime(startTime);
        appSleepRangeVo.setEndTime(endTime);

        //判断睡眠状态
        if(sleepDuration >= OldmanAppConstant.DEEP_SLEEP_STANDARD){
            appSleepRangeVo.setSleepStatus(OldmanAppConstant.DEEP_SLEEP_STATUS);
        }else if(sleepDuration>=OldmanAppConstant.LIGHT_SLEEP_STANRDARD && sleepDuration < OldmanAppConstant.DEEP_SLEEP_STANDARD){
            appSleepRangeVo.setSleepStatus(OldmanAppConstant.DEEP_SLEEP_STATUS);
        }else{
            appSleepRangeVo.setSleepStatus(OldmanAppConstant.DEEP_SLEEP_STATUS);
        }
        return appSleepRangeVo;
    }
}
